package com.faxsun.web.endpoint;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import javax.servlet.AsyncContext;

import mblog.core.pojos.Comment;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.faxsun.core.persist.entity.LiveManagerPO;
import com.faxsun.core.persist.entity.LiveMsgPO;
import com.faxsun.core.pojos.enums.CommentType;
import com.faxsun.core.service.CommentService;
import com.faxsun.core.service.LiveAdminService;
import com.faxsun.core.service.LiveMsgService;
import com.faxsun.core.service.impl.LiveAdminServiceImpl.Roles;
import com.faxsun.web.endpoint.entity.LiveCommentJSON;
import com.faxsun.web.endpoint.entity.LiveMsgContent;
import com.faxsun.web.endpoint.entity.LiveMsgJSON;

/**
 * Async query comment from database for "suspend" servlet context
 * @author leima
 *
 */
public class CommentAsyncTask implements Runnable{  
    
    private static final Logger log=LoggerFactory.getLogger(CommentAsyncTask.class);
    
    private CommentService commentService;  
    
    private LiveAdminService liveAdminService; 
    
    private LiveMsgService liveMsgService;
    
    private static final int msgLength = 20;
    
    public CommentAsyncTask(CommentService commentService, LiveAdminService liveAdminService, LiveMsgService liveMsgService){
        this.commentService = commentService;
        this.liveAdminService = liveAdminService;
        this.liveMsgService = liveMsgService;
    }
    
    public static CountDownLatch cdl = null;
    
    public static void init(int poolSize){
        cdl = new CountDownLatch(poolSize);
    }

    @Override
    public void run() {
        while (!LiveCommentEndpoint.shutdown) {
            CommentTaskItem item = null;
            try {
                try {
                    item = LiveCommentEndpoint.asyncItemList.poll(LiveCommentEndpoint.timeoutVal / 10,
                            TimeUnit.MILLISECONDS);
                    log.debug("take another CommentAsyncTask at run");
                } catch (Throwable e1) {
                    log.error("CommentAsyncTask take error", e1);
                    if (item != null) {
                        try {
                            LiveCommentEndpoint.asyncItemList.put(item);
                        } catch (Throwable e) {
                            log.error("CommentAsyncTask puts error, abandon response", e);
                        }
                    }
                }
                if (item != null) {
                    LiveCommentJSON data = null;
                    try {
                        data = item.getData(commentService, liveAdminService, liveMsgService);
                    } catch (Throwable t) {
                        log.error("CommentAsyncTask get data error", t);
                        if (item != null) {
                            try {
                                LiveCommentEndpoint.asyncItemList.put(item);
                            } catch (Throwable e) {
                                log.error("CommentAsyncTask puts error, abandon response", e);
                            }
                        }
                    }

                    if (data != null) {
                        @SuppressWarnings("rawtypes")
						List comments = (List) data.getComments_blacklist().get(LiveCommentJSON.COMMENTS);

                        Comment latestCmt = null;
                        if (comments != null && comments.size() > 0) {
                            latestCmt = (Comment) comments.get(0);
                        }

                        long now = System.currentTimeMillis();

                        long elpasd = (now - item.startTime);

                        if (elpasd < LiveCommentEndpoint.timeoutVal
                                && (latestCmt == null || latestCmt.getId() <= item.startId)) {
                            try {
                                LiveCommentEndpoint.asyncItemList.put(item);
                            } catch (Throwable e) {
                                log.error("CommentAsyncTask puts error, abandon response", e);
                            }
                        } else {
                            item.completeRequest(data, true);
                        }
                    }
                }
                Thread.sleep(100);
            } catch (Throwable e) {
                log.error("CommentAsyncTask run error", e);
                if (item != null) {
                    try {
                        LiveCommentEndpoint.asyncItemList.put(item);
                    } catch (Throwable t) {
                        log.error("CommentAsyncTask puts error, abandon response", t);
                    }
                }
            }
        }
        cdl.countDown();
        return;
    }
    
    public static class CommentTaskItem{
    	
    	private static final Logger log=LoggerFactory.getLogger(CommentTaskItem.class);
    	
        public AsyncContext context;
        public Long liveId;
        public Long startId;
        public Long endId;
        public int size;
        public Long startTime;
        
        public CommentTaskItem(AsyncContext context, Long startTime,
                Long liveId , Long startId, Long endId, int size){
            this.context = context;
            this.startTime = startTime;
            this.liveId = liveId;
            this.startId = startId;  
            this.size = size;
            this.endId = endId;
        }
        
        public LiveCommentJSON getData(CommentService commentService, LiveAdminService liveAdminService, LiveMsgService liveMsgService){
            List<Long> blacklist = liveAdminService.getTalkDisabledUserId(liveId);   
            List<Integer> types = new ArrayList<Integer>(Arrays.asList(new Integer[]{CommentType.LIVE.getIntValue(), CommentType.LIVEMSG.getIntValue()}));
            List<Comment> comments = commentService.getCommentsFrom(liveId, startId, endId, size, types, 1, blacklist);
            Map<String, LiveMsgJSON> livemsgs = null;
            for(Comment c : comments){               
                if(c.getType() == CommentType.LIVEMSG.getIntValue()){
                   LiveMsgPO lmpo = liveMsgService.findById(c.getToId());
                   if(lmpo != null){
                       LiveMsgJSON original = LiveMsgJSON.parse(lmpo);
                       
                       LiveMsgJSON liveMsg = new LiveMsgJSON();
                       liveMsg.setId(c.getToId());                   
                       
                       LiveMsgContent lmc = new LiveMsgContent();
                       String originalText = original.getContent().getText();
                       if(originalText != null && !originalText.isEmpty()){
                          int sumLength = originalText.length() <= msgLength? originalText.length() : msgLength;
                          lmc.setText(originalText.substring(0, sumLength)); 
                       }
                       if(original.getContent().getUrl() != null && original.getContent().getUrl().size() > 0){
                          lmc.setUrl(original.getContent().getUrl());
                       }
                       liveMsg.setContent(lmc);

                       if(livemsgs == null){
                          livemsgs = new HashMap<String, LiveMsgJSON>(); 
                       }
                       livemsgs.put(String.valueOf(c.getToId()), liveMsg);
                   }else{
                       log.error("failed to find original live message with id:" + c.getToId());
                   }
                }else if(c.getType() == CommentType.LIVE.getIntValue()){
                   if(c.getContent().contains(CommentService.REPLY_TOKEN)){
                      String[] tmp = c.getContent().split(CommentService.REPLY_TOKEN);

                      if (tmp.length < 3) {
                          c.setContent("回复" + tmp[1] + ":");
                      } else {
                          c.setContent("回复" + tmp[1] + ":" + tmp[2]);
                      }
                   }
                }
            }
            
            List<LiveManagerPO> adminlist = liveAdminService.getLiveManagers(liveId);//getLiveManagersIds(liveId);
            List<Long> mgrListRet = new ArrayList<Long>(); 
            Long adminId = -1L;
            if(adminlist != null && adminlist.size() > 0){
               for(LiveManagerPO lmpo : adminlist){
                   if(lmpo.getManagerRole().equals(Roles.ADMIN.toString())){
                      adminId = lmpo.getUserId();  
                   }else{
                      mgrListRet.add(lmpo.getUserId()); 
                   }
               }                
            }
                         
            LiveCommentJSON data = new LiveCommentJSON(comments, blacklist, mgrListRet, livemsgs, adminId);
            
            return data;
        }
        
        public void completeRequest(LiveCommentJSON data, boolean requeueOnError){
            AsyncContext asyncContext = context;

            asyncContext.getResponse().setContentType("application/json");
            asyncContext.getResponse().setCharacterEncoding("UTF-8");
            
            String jsonData = JSON.toJSONString(data);
            
            try {
                asyncContext.getResponse().getWriter().print(jsonData);
                log.debug("send message:"+jsonData);
                asyncContext.complete();
            } catch (Throwable e) {
                log.error("complete error CommentTaskItem at completeRequest", e);      
                if(requeueOnError){
                    try {
                        LiveCommentEndpoint.asyncItemList.put(this);
                    } catch (Throwable e1) {
                        log.error("put error another CommentTaskItem at completeRequest, abandon response", e);                        
                    }
                }
            }
        }
        
    }
    
}